package com.yun.common;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import javax.transaction.Transactional;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * 基础Service
 *
 * @author WUWY
 * @create 2018-05-12 上午11:25
 **/
@Transactional(rollbackOn = Exception.class)
public abstract class BaseService<T extends BaseModel<I>, I extends Serializable> {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private BaseRepository<T, I> baseRepository;

    public T findOne(I id) {
        checkId(id);
        return baseRepository.findById(id).get();
    }

    public T findStrictOne(I id) {
        T t = findOne(id);
        if (null == t) {
            throw new RuntimeException("【" + id + "】数据找不到");
        }
        return t;
    }

    public List<T> findAll() {
        return baseRepository.findAll();
    }

    public Page<T> page(Pageable pageable) {
        return baseRepository.findAll(pageable);
    }

    public T add(T t) {
        if (null != t.getId() && exists(t.getId())) {
            throw new RuntimeException("【" + t.getId() + "】数据已存在");
        }
        baseRepository.save(t);
        return t;
    }

    public T update(T t) {
        checkId(t.getId());
        if (!exists(t.getId())) {
            throw new RuntimeException("【" + t.getId() + "】数据找不到");
        }
        baseRepository.save(t);
        return t;
    }

    public T update(I id, Map<String, Object> map) {
        T old = findStrictOne(id);
        map.remove(id);
        T one = createDomainFromOldAndMap(old, map);
        doUpdateMap(old, one, map);
        return update(one);
    }

    public void delete(T t) {
        if (null == t) {
            return;
        }
        baseRepository.delete(t);
    }

    public void delete(I id) {
        baseRepository.deleteById(id);
    }

    public void deleteMore(Iterable<I> ids) {
        for (I id : ids) {
            delete(id);
        }
    }

    protected void doUpdateMap(T old, T one, Map<String, Object> map) {

    }

    protected boolean exists(I id) {
        return findOne(id) != null;
    }


    protected void checkId(I id) {
        if (id == null) {
            throw new RuntimeException("id参数不存在");
        }
    }

    private T createDomainFromOldAndMap(T oldDomain, Map<String, Object> map) {
        try {
            T newDomain = (T) oldDomain.getClass().newInstance();
            BeanUtils.copyProperties(oldDomain, newDomain);
            String json = objectMapper.writeValueAsString(map);
            return objectMapper.readerForUpdating(newDomain).readValue(json);
        } catch (IllegalArgumentException | IOException e) {
            throw new RuntimeException("无效参数");
        } catch (InstantiationException | IllegalAccessException e) {
            String message = "类[" + oldDomain.getClass().getCanonicalName() + "]找不到可访问无参构造器";
            throw new RuntimeException("内部代码错误");
        }
    }


}

